いやというほどわかる低水準3Dグラフィックス Direct3D12
Direct3D12の初学者向けに、なぜ今ローレベルグラフィックスなのか?ということから始まって理論からDirect3D12による実装まで解説。オンラインのサンプルも付属。 の読書メモ。勘違いでミスがあるかも。
モチベーション(p.3)
VRが流行って周りにGPUを買っている同僚が現れた
アプリを書いている人が低水準グラフィックスライブラリをいきなり使おうとしてもさっぱり理解できないはず
アプリ屋とハード屋の考えていることは180度違う。
VR盛り上げたいので書いた
対象読者
リアルタイムグラフィクスを実現するアプリケーション開発者のうち、直接グラフィクスライブラリの使用・選定に関わる人
⻑い前振り- Direct3D12とは何か
基素.iconこの章は歴史の説明。かなり詳しくて読み解けないところもちらほら。
3Dグラフィックスライブラリの大まかな歴史
(ハードウェア)1980s Sillicon Graphics(のちのSGI)のワークステーションに乗ったのが普及GPUのはしり(GPUではない)
IRIXとOpenGL
UNIX
IRIX GLライブラリ
1992 SGIは自社開発のIRIS GLをOpenGLとして業界標準仕様を策定 Client/Server アーキテクチャ
OpenGLは抽象化が得意(リソース管理)
リソースの実態がどこにあるのかプログラマは意識しないで良い
テクスチャもバッファも整数識別子
ハードウェアはグラフィックの処理が得意
OpenGLはステートフルなAPI
マルチスレッドが不可能
暗黙のコンテキストがある
タイミング依存
1994 OpenGL 1.0
1999年ごろはスレッドを使う利点は全くなかった
マルチコアプロセッサ登場 Athron X2まで時代を下る
VoodooとGlide, その他の3DグラフィックスエンジンとDirect3D ワークステーションではなく、PCでも3D描画の試みは行われていた
3Dアクセラレータ
3Dアクセラレーションにもを行うボードを利用
大ヒット製品は3dfx社のVoodooチップ(chip is not board)
Voodooを使うためにはGlideを使う必要あり
ライセンス契約をしたゲームベンダのみアクセスできた
評価が高かった(90ごろ〜98まで覇権ブランド)
98年から1-2年でGeForce + Direct3Dにつき崩され、99年にOSS化
Glideの正体は、ユーザー空間のみでGPUのコマンドを組み上げ、(OSが許せば)バスを制御してGPUプリミティブ描画コマンドを送信するという極めて低水準のライブラリ
この発想は今日まで、とても重要なアイデアのひとつになりました
WindowsとDirect3DとOpenGL
WIndows95 OSR2 OpenGL 1.1が実装
WIndows向けCADはワークステーション用のWindowsNTで運用されていた
プロセス暗黙に関連づけられたリソース管理ができる
Windows95だとリソース管理は厳しかった
OpenGLの実装OpenGL32.dllはMicrosoftの実装だったが、処理が遅かった
処理の多くがドライバ依存でAPIコール毎にドライバを呼び出した
ドライバはRing0なのでコンテキストスイッチが高かった
ユーザーは「OpenGLは遅い」と印象付けられた
おそらくこれはMicrosoftの意図的な戦略
SGIはsyscallの頻度削減は可能と主張
10年後、Windows Vistaでユーザー空間で動作するOpenGL installable Client Driverが出て解消された
Microsoftは独自にDirect3Dを作った
コンテキストスイッチのオーバーヘッドを減らすため、ハードウェアベンダにはユーザ空間で動くドライバの開発を義務付けた
Direct3Dは同時期のVoodoo + Glideに負けていた
ハードウェアベンダのデバイスドライバの最適化が甘かった
「ドライバのバージョンでゲームが動かない」のはこれが原因
ハードウェア性能が同じでも「ライブラリ+ドライバ」のオーバーヘッドが2倍になれば表示できるオブジェクトは半分になる
ゲームのプログラムは行儀の悪いものもあるが、それでも互換性を保ちつつ動かさないといけないので大変
Voodooの失墜とGeForceの時代
1998 3dfxは単体でVGAも出力できるビデオカード参入を発表。他ベンダーは警戒
MicrosoftはNVIDIAと協力して最適化されたハードウェアとAPI(DIrect3D 7.0)を準備 Mirosoftの弱点だった高速なチップとドライバを手に入れた
当時のPC雑誌やメディアはGeforce 256の話題でいっぱいで、Microsoft+NVIDIAは大成功
当時のPC市場で3D描画性能はベンチマークの肥やしだったのだが
ベンチマークのスコアで売り上げが大きく変わった
基素.icon 使わない3Dのスコアでも上がったの?
ベンダはベンチマークのスコアのことだけを考え、不正も行われた
API戦争後の傷跡
2000年代前半 日本市場において3DはPCは負のイメージがついた
絵が汚い・重い・相性が悪いと動かない・PCが不安定になる
教訓 良いハードだけでなく良いライブラリ、ドライバがないと市場が死ぬ
主要な顧客はCAD、科学技術計算
パフォーマンスより安定性・クロスプラットフォーム重視
OpenGLの仕様策定の仕組みによって、先進的な機能はDirect3DよりOpenGLで利用できた
OSのランタイム対応を待たなくて良い
ベンダが提案してドライバ実装すればアプリはすぐ使える
プログラマブルシェーダーのコンシューマー市場入り
2000-02 DirectX 8.0-9.0 リアルタイムシェーダサポート
GPU向けのアセンブリっぽい言語
2003 OpenGL 1.5の拡張プログラマブルシェーダ ARB_shader_objects
ハードウェアベンダ依存のシェーダーアセンブリの標準は難しかった
2004 OpenGL 2.0仕様書でAPIが明らかになる
2006 GLSLの使用決定 OpenGL 2.1で標準化 2000s 高解像度モバイルデバイスがはやる。それをターゲットにOpenGL ES 1.0
OpenGL 1.3のサブセット
GLES1.0はただAPIを減らしただけの代物であり、実用的でもなく、歴史的な意味があったとも思えません。サブセットといっても多くのAPIがそのまま残っており、仕様通りに実装するコストも、多様なカラーフォーマットの運用も現実的ではありませんでした。
2007 GLES2,0
OpenGL 1.5のサブセット
固定パイプラインを削減して頂点シェーダーを利用するようになる
APIも要望が高いもの以外削減してシンプル化
多くのスマートデバイスのみならずWebGLでもGLES2.0が利用可能になった
ハードウェアの進化
minor
シェーダー長、定数パラメータ容量制限の撤廃
パイプラインの拡張
GPUの命令追加
メモリアクセス(Shader Model 5.0 DirextX11 OpenGL4世代)
GPUからアクセス可能なメモリはL/Wできる
シェーダーの応用可能性が飛躍的に伸びた
それまではサンプラ経由でテクスチャのピクセルを読み出すだけだった
さらなる低水準APIの時代
CPUのクロックが上がらなくなった(ハードウェア的進化の限界)
3Dグラフィックスライブラリとスレッドが再考された
DIrect3D11
コマンドバッファをドライバからアプリに公開してAPI呼び出しオーバーヘッドを削減
Deferred Context
別スレッドでコマンド構築をできるようにする
CPUはシリアルな要求に対してGPUより遅い
マルチパスレンダリング、ステレオ立体視などで呼び出しオーバーヘッドがn倍に増える
GPUのインタフェースはGladeからあまり変わっていない
GPUのグラフィックスコマンドをコマンドバッファをFIFOでバスに流すというアプローチ 他にはDMAコントローラを使って非同期に転送する方法もあるがストリーミングにはFIFOの方が重要 みんなこのアプローチを取るようになった
GPUのオーバーヘッドを減らせるから
スレッドに対してスケールが容易・再利用可能
欠点
コマンドバッフェに記録できないコマンドがある
編集できないコマンドバッファがある(この問題はテクニックで回避できる)
階層化して繋ぎかえることで実現する
Direct3D11
以上の歴史が示すアイデアのモダンなアプローチ
Immediate Context
目的:マルチスレッドでコア数に対してスケールする
他スレッドでコマンドバッファを構築し、接続することでGPUに投入可能になる
11以前の描画方法はこっち相当
Deferred Context
ID3D11DeviceContextへのMap/Unmapの追加
いずれかに確保されているメモリページを、CPU側のアドレス変換テーブルに対してmap.unmapする
GPU側に確保したメモリへCPUからアクセス
CPUとGPUのメモリアドレス空間は独立している
Map/Unmapはこれらの返還を隠蔽する
DefferedContextに対するMAP
アプリケーションはGPU利用中のデータを書き換えないように実装する仕様だった
しかしこれが困難だった
どうすればよかったか
アプリケーションによるメモリ破壊にた対象する
トランポリンバッファの確保
2015 Direct3D12
おこまでの歴史的発展から、問題の整理すると
ドライバのリソース管理が複雑
GPUを同期をちゃんとしたい
Deffered Contextのためのリソース割り当て
アプリケーションによる帯域的リソース管理
Deffered Contextを使ったコマンドバッファのマルチスレッド化
2013 Mantleはこれらの問題を回避した。同時期に多発的に同じようなライブラリをリリースした。これは前からあったオリジナルのアイデアがMantleを通じて広まったと筆者は考えている OpenGLを低水準ライブラリにするのは不可能に近い
OpenGLの仕様はインタフェース
よって、レンダリング結果をどう画面に表示するかはプラットフォーム依存
Windows WGL/GLUT
Linux GLX/GLUT
2013年AMDはGPU命令の中間表現を探していた
他社GPUでも使えるようにしたかった
純粋に技術的に可能かどうかで言えばIntelとかNVIDIAでもMantleを使う事ができる(当然ながらこれらのベンダーがMantle対応ドライバを提供する必要があるが)
AMDのAPIをSPIRに乗せて標準化し、Vulkanが誕生した
未来
ただのバージョンとは言えない。後戻りできない決断
Windows10の3D統合はかつてSGIがIRIXでやったこと
ファーストステップ
仮定 初期化などの準備は完了している
リソースビュー
パイプラインステートオブジェクト
コマンドキュー
スワップチェイン
フェンス
初期化
リソースバインディング
入門者がつまづくポイント
リソースのバインディングとはどういうことか
役者たち
ルートシグネチャの紹介
デスクリプタ
デスクリプタヒープ
デスクリプタテーブル
ルートシグネチャ
応用
メッシュごとの行列の置き換え
リソース管理
メモリを確保するということ
ヒープ
GPUが所有するメモリ
GPUが所有しないメモリ?(Map/Unmap)
データのアップロードとリソースの状態遷移
リソースの種類とバジェットの消費
CreateCommittedResource
CreateReservedResource/CreatePlacedResource
リソースの戦略
再帰描画とコマンドバッファ
デプスバッファの状態
シャドウパスのパイプラインステートオブジェクト
シーンパス
大きなポリゴンとGPUのパフォーマンス
再帰描画とコマンドバッファ
コマンドバッファの再利用
バンドルの注意点
パフォーマンス上の注意
バンドルの構築
レイアウト
立体視とコマンドバッファ